跳到主要内容

H2 数据库学习

参考资料 H2 数据库使用简介 参考资料 H2数据库使用指南

什么是 H2 数据库

H2 是一个开源的嵌入式数据库引擎,采用 Java语言编写,不受平台的限制,它本身只是一个类库,即只有一个 jar 文件,可以直接嵌入到应用项目中。H2 主要有如下三个用途:

  • 第一个用途:也是最常使用的用途就在于可以同应用程序打包在一起发布,这样可以非常方便地存储少量结构化数据。
  • 第二个用途:用于单元测试。启动速度快,而且可以关闭持久化功能,每一个用例执行完随即还原到初始状态。
  • 第三个用途:作为缓存,即当做内存数据库,作为 NoSQL 的一个补充。当某些场景下数据模型必须为关系型,可以拿它当 Memcached 使,作为后端 MySQL/Oracle 的一个缓冲层,缓存一些不经常变化但需要频繁访问的数据,比如字典表、权限表。

配置环境

<properties>
<h2.version>1.4.200</h2.version>
</properties>


<!--添加H2依赖-->
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<version>${h2.version}</version>
<scope>test</scope>
</dependency>

H2 数据库常用的类型和函数

H2 数据库常用数据类型

INT 类型:对应java.lang.Integer

REAL 类型:对应java.lang.Float

DOUBLE 类型:对应java.lang.Double

DECIMAL 类型:对应java.math.BigDecimal,比如DECIMAL(20,2)

CHAR 类型:对应java.lang.String,比如CHAR(10)

VARCHAR 类型:对应java.lang.String

VARCHAR_IGNORECASE 类型:对应java.lang.String,忽略大小写

BOOLEAN 类型:对应java.lang.Boolean

TIME 类型:对应java.sql.Time,当转换成java.sql.Date时,日期会设置成1970-01-01

DATE 类型:对应java.sql.Date,格式为yyyy-MM-dd,其时间默认为00:00:00

TIMESTAMP 类型:对应java.sql.Timestamp,格式为yyyy-MM-dd hh:mm:ss[.nnnnnnnnn],也支持java.util.Date

TINYINT 类型:对应java.lang.Byte,-128 to 127

SMARTINT 类型:对应java.lang.Short,-32768 to 32767

BIGINT 类型:对应java.lang.Long

IDENTITY 类型:自增类型,对应java.lang.Long,值范围-9223372036854775808 to 9223372036854775807

BINARY 类型:二进制字节存储,最大不超过2GB,且完全保存在内存,比如BINARY(1000)

BLOB 类型:对应java.sql.Blob,与BINARY相似,但针对很大的数据(如文件或图像),且不完全保存在内存,使用PreparedStatement.setBinaryStream来保存数据。

CLOB 类型:与VARCHAR相似,但适用于保存很大的数据,且数据不完全保存在内存。用于任意尺寸的XML或HTML文档、文本文件等。使用PreparedStatement.setCharacterStream保存数据。

OTHER 类型:对应java.lang.Object,用于存储序列化的Java对象,使用的是字节数组,客户端只能做序列化或反序列化,使用getObject反序列化,使用PreparedStatement.setObject存储数据。

UUID 类型:对应java.util.UUID,128位的值,可以使用PreparedStatement.setBytes或setString或setObject(uuid)保存数据,使用ResultSet.getObject取回数据。

ARRAY 类型:对应java.lang.Object[]

H2 常用函数

CURRENT_DATE:取当前日期

CURRENT_TIME:取当前时间

CURRENT_TIMESTAMP:取当前日期时间

LOWER:字符串小写

UPPER:字符串大写

CONCAT:字符串连结

CHAR:ASCII值转字符

ASCII:字符转ASCII值

ENCRYPT:加密函数,支持AES算法,Block尺寸为16字节,

比如 CALL ENCRYPT('AES', '00', STRINGTOUTF8('Test'))

DECRYPT:解密函数,支持AES算法,Block尺寸为16字节,

比如:CALL TRIM(CHAR(0) FROM UTF8TOSTRING(DECRYPT('AES', '00', '3fabb4de8f1ee2e97d7793bab2db1116')))

HASH:哈希函数,只支持SHA256算法,比如CALL HASH('SHA256', STRINGTOUTF8('Password'), 1000)

MAX:求最大

MIN:求最小

SUM:求和

CURRENT_USER:返回当前用户

H2VERSION:返回H2数据库的版本

DISK_SPACE_USED:返回表使用的磁盘空间尺寸,比如CALL DISK_SPACE_USED('my_table');

DATABASE_PATH:返回数据库文件的路径和数据库名,比如CALL DATABASE_PATH();

运行模式与运行方式

运行模式

1、内嵌模式(Embedded Mode):内嵌模式下,应用和数据库同在一个 JVM 中,通过 JDBC 进行连接。可持久化,但同时只能一个客户端连接。内嵌模式性能会比较好。

2、服务器模式(Server Mode):使用服务器模式和内嵌模式一样,只不过它可以跑在另一个进程里。

3、混合模式:第一个应用以内嵌模式启动它,对于后面的应用来说它是服务器模式跑着的。混合模式是内嵌模式和服务器模式的组合。第一个应用通过内嵌模式与数据库建立连接,同时也作为一个服务器启动,于是另外的应用(运行在不同的进程或是虚拟机上)可以同时访问同样的数据。第一个应用的本地连接与嵌入式模式的连接性能一样的快,而其它连接理论上会略慢。

连接方式

参考资料 官方文档 DatabaseURL

1、以嵌入式(本地)连接方式连接 H2 数据库:这种连接方式默认情况下只允许有一个客户端连接到 H2数据库,有客户端连接到 H2数据库之后,此时数据库文件就会被锁定,那么其他客户端就无法再连接了。

连接语法:

jdbc:h2:[file:][<path>]<databaseName>

例如:
jdbc:h2:~/test    // 连接位于用户目录下的test数据库
jdbc:h2:~/test
jdbc:h2:file:/data/sample
jdbc:h2:file:C:/data/sample (Windows only)

2、使用 TCP/IP 的服务器模式(远程连接)方式连接 H2数据库:这种连接方式就和其他数据库类似了,是基于 Service 的形式进行连接的,因此允许多个客户端同时连接到 H2数据库。

连接语法:

jdbc:h2:tcp://<server>[:<port>]/[<path>]<databaseName>
jdbc:h2:tcp://localhost//test<br/>jdbc:h2:tcp://dbserv:8084//sample
jdbc:h2:tcp://localhost/mem:test

范例:
jdbc:h2:tcp://localhost/~/test

3、H2数据库的内存模式

(1)、H2数据库被称为内存数据库,因为它支持在内存中创建数据库和表。 (2)、如果使用 H2 数据库的内存模式,那么我们创建的数据库和表都只是保存在内存中,一旦服务器重启,那么内存中的数据库和表就不存在了。

连接语法:

私有的:
jdbc:h2:mem:

命名:
jdbc:h2:mem:<databaseName>
jdbc:h2:mem:test_mem

创建本地文件数据库

Connection conn = null;
try{
Class.forName("org.h2.Driver");
conn = DriverManager.getConnection("jdbc:h2:~/test", "sa", "sa");

//do your business
} catch (Exception e){
e.printStackTrace();
} finally {
try {
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}

创建本地内存数据库

Connection conn = null;
try{
Class.forName("org.h2.Driver");
conn = DriverManager.getConnection("jdbc:h2:mem:test_mem", "sa", "sa");
// do your business
} catch (Exception e){
e.printStackTrace();
} finally {
try {
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}

使用实例

public class Main {

/**
* 以嵌入式(本地)连接方式连接H2数据库
*/
private static final String JDBC_URL = "jdbc:h2:mem:test_mem";
private static final String USER = "root";
private static final String PASSWORD = "root";
private static final String DRIVER_CLASS = "org.h2.Driver";

public static void main(String[] args) throws SQLException, ClassNotFoundException {
Class.forName(DRIVER_CLASS);
Connection conn = DriverManager.getConnection(JDBC_URL, USER, PASSWORD);
Statement statement = conn.createStatement();
statement.execute("DROP TABLE IF EXISTS USER_INF");
statement.execute("CREATE TABLE USER_INF(id INTEGER PRIMARY KEY, name VARCHAR(100), sex VARCHAR(2))");

statement.executeUpdate("INSERT INTO USER_INF VALUES(1, 'tom', '男') ");
statement.executeUpdate("INSERT INTO USER_INF VALUES(2, 'jack', '女') ");
statement.executeUpdate("INSERT INTO USER_INF VALUES(3, 'marry', '男') ");
statement.executeUpdate("INSERT INTO USER_INF VALUES(4, 'lucy', '男') ");

ResultSet resultSet = statement.executeQuery("select * from USER_INF");

while (resultSet.next()) {
System.out.println(
resultSet.getInt("id") + ", " + resultSet.getString("name") + ", " + resultSet.getString("sex"));
}

statement.close();
conn.close();
}
}